<?php

namespace app\system\service;

use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\SignatureInvalidException;
use think\Config;

class TokenService
{
    protected string $salt;

    public function __construct()
    {
        //从配置信息这种或取唯一字符串，你可以随便写比如md5('token')
        $this->salt = md5(config('jwt.salt'));
    }


    /**
     * 生成访问令牌或刷新令牌
     * @param int $uid 用户ID
     * @param string $type 令牌类型 ('access' 或 'refresh')
     * @return string
     */
    function generateToken($uid, $type = 'access'): string
    {
        $time = time();
        $expTime = $type === 'access' ? config('jwt.add') : config('jwt.refreshAdd');

        $payload = [
            'iss' => config('jwt.iss'),  // 签发者
            'sub' => config('jwt.sub'),  // 主题
            'iat' => $time,              // 签发时间
            'nbf' => $time,              // 生效时间
            'exp' => $time + $expTime,   // 截止时间
            'data' => ['uid' => $uid]
        ];

        $keyId = config('jwt.keyId');
        return JWT::encode($payload, $this->salt, config('jwt.hash'), $keyId);
    }

    /**
     * 校验token时效性
     */
    public function checkToken($token): array
    {
        $token = str_replace("Bearer ", "", $token);
        $status = array("success" => false);
        try {
            JWT::$leeway = 60;//当前时间减去60，留着空余时间
            $decoded = JWT::decode($token, new Key($this->salt, 'HS256'));
            $arr = (array)$decoded;
            $res['success'] = true;
            $res['data'] = ($arr['data']);
            return ($res);
        } catch (SignatureInvalidException $e) { //签名不正确
            $status['message'] = "签名不正确";
            return $status;
        } catch (BeforeValidException $e) { // 签名在某个时间点之后才能用
            $status['message'] = "token失效";
            return $status;
        } catch (ExpiredException $e) { // token过期
            $status['message'] = "token失效";
            return $status;
        } catch (\Exception $e) { //其他错误

            $status['message'] = "未知错误";
            return $status;
        }
    }

    /**
     * 使用旧的刷新令牌来生成新的访问令牌和刷新令牌
     *
     * @param string $refreshToken
     * @return array
     */
    public function refreshToken($refreshToken): array
    {

        $decoded = JWT::decode($refreshToken, new Key($this->salt, 'HS256'));
        // 如果刷新令牌有效，创建新的访问令牌和刷新令牌
        $userId = $decoded->data->uid;  // 假设你的刷新令牌中存有userId
        $newAccessToken = $this->generateToken($userId);
        $newRefreshToken = $this->generateToken($userId, 'refresh');
        $newDecoded = JWT::decode($newAccessToken, new Key(md5(config('jwt.salt')), 'HS256'));
        return [
            'accessToken' => $newAccessToken,
            'refreshToken' => $newRefreshToken,
            'expires' => date("Y/m/d H:i:s", $newDecoded->exp)
        ];

    }
}